"""配置管理工具

提供配置文件加载、环境变量处理、配置验证等功能
"""

import os
import json
import yaml
from typing import Any, Dict, List, Optional, Union
from pathlib import Path
from .exceptions import ConfigurationException
from .logger import get_logger
from .validators import (
    StringValidator, IntegerValidator, FloatValidator, 
    BooleanValidator, ListValidator, DictValidator
)

logger = get_logger(__name__)

class ConfigManager:
    """配置管理器"""
    
    def __init__(self, config_file: Optional[str] = None, 
                 env_prefix: str = 'BLOCKCHAIN_MIDDLEWARE'):
        """初始化配置管理器"""
        self.config_file = config_file
        self.env_prefix = env_prefix
        self._config = {}
        self._validators = {}
        self._loaded = False
        
        # 默认配置
        self._default_config = {
            'app': {
                'name': 'Blockchain Middleware',
                'version': '1.0.0',
                'debug': False,
                'host': '0.0.0.0',
                'port': 5000
            },
            'database': {
                'mongodb': {
                    'host': 'localhost',
                    'port': 27017,
                    'database': 'blockchain_middleware',
                    'username': '',
                    'password': '',
                    'auth_source': 'admin',
                    'replica_set': '',
                    'ssl': False,
                    'connection_timeout': 30000,
                    'server_selection_timeout': 30000,
                    'max_pool_size': 100,
                    'min_pool_size': 10
                }
            },
            'security': {
                'jwt': {
                    'secret_key': 'your-secret-key-here',
                    'algorithm': 'HS256',
                    'access_token_expire': 3600,
                    'refresh_token_expire': 86400
                },
                'api_key': {
                    'enabled': True,
                    'header_name': 'X-API-Key'
                },
                'rate_limiting': {
                    'enabled': True,
                    'requests_per_minute': 100,
                    'burst_size': 200
                }
            },
            'blockchain': {
                'adapters': {
                    'fisco_bcos': {
                        'enabled': True,
                        'node_url': 'http://localhost:8545',
                        'chain_id': 1,
                        'group_id': 1,
                        'timeout': 30
                    },
                    'chainmaker': {
                        'enabled': False,
                        'node_url': 'localhost:12301',
                        'chain_id': 'chain1',
                        'org_id': 'org1',
                        'timeout': 30
                    }
                },
                'performance': {
                    'target_tps': 1000,
                    'max_connections': 100,
                    'request_timeout': 30,
                    'retry_attempts': 3,
                    'retry_delay': 1
                }
            },
            'monitoring': {
                'enabled': True,
                'metrics_interval': 60,
                'health_check_interval': 30,
                'alert_thresholds': {
                    'cpu_usage': 80,
                    'memory_usage': 85,
                    'disk_usage': 90,
                    'response_time': 5000,
                    'error_rate': 5
                }
            },
            'logging': {
                'level': 'INFO',
                'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                'file': {
                    'enabled': True,
                    'path': 'logs/app.log',
                    'max_size': '10MB',
                    'backup_count': 5
                },
                'console': {
                    'enabled': True
                }
            }
        }
        
        # 设置验证器
        self._setup_validators()
    
    def _setup_validators(self):
        """设置配置验证器"""
        self._validators = {
            'app.name': StringValidator(min_length=1, max_length=100),
            'app.version': StringValidator(pattern=r'^\d+\.\d+\.\d+$'),
            'app.debug': BooleanValidator(),
            'app.host': StringValidator(min_length=1),
            'app.port': IntegerValidator(min_value=1, max_value=65535),
            
            'database.mongodb.host': StringValidator(min_length=1),
            'database.mongodb.port': IntegerValidator(min_value=1, max_value=65535),
            'database.mongodb.database': StringValidator(min_length=1),
            'database.mongodb.connection_timeout': IntegerValidator(min_value=1000),
            'database.mongodb.max_pool_size': IntegerValidator(min_value=1, max_value=1000),
            
            'security.jwt.secret_key': StringValidator(min_length=32),
            'security.jwt.algorithm': StringValidator(),
            'security.jwt.access_token_expire': IntegerValidator(min_value=300),
            'security.jwt.refresh_token_expire': IntegerValidator(min_value=3600),
            
            'security.rate_limiting.enabled': BooleanValidator(),
            'security.rate_limiting.requests_per_minute': IntegerValidator(min_value=1),
            'security.rate_limiting.burst_size': IntegerValidator(min_value=1),
            
            'blockchain.performance.target_tps': IntegerValidator(min_value=1),
            'blockchain.performance.max_connections': IntegerValidator(min_value=1),
            'blockchain.performance.request_timeout': IntegerValidator(min_value=1),
            'blockchain.performance.retry_attempts': IntegerValidator(min_value=0, max_value=10),
            
            'monitoring.enabled': BooleanValidator(),
            'monitoring.metrics_interval': IntegerValidator(min_value=10),
            'monitoring.health_check_interval': IntegerValidator(min_value=5),
            
            'monitoring.alert_thresholds.cpu_usage': IntegerValidator(min_value=1, max_value=100),
            'monitoring.alert_thresholds.memory_usage': IntegerValidator(min_value=1, max_value=100),
            'monitoring.alert_thresholds.disk_usage': IntegerValidator(min_value=1, max_value=100),
            'monitoring.alert_thresholds.response_time': IntegerValidator(min_value=100),
            'monitoring.alert_thresholds.error_rate': IntegerValidator(min_value=1, max_value=100),
            
            'logging.level': StringValidator(),
            'logging.format': StringValidator(min_length=1),
            'logging.file.enabled': BooleanValidator(),
            'logging.file.path': StringValidator(min_length=1),
            'logging.file.backup_count': IntegerValidator(min_value=1, max_value=100),
            'logging.console.enabled': BooleanValidator()
        }
    
    def load_config(self, config_file: Optional[str] = None) -> Dict[str, Any]:
        """加载配置"""
        if config_file:
            self.config_file = config_file
        
        # 从默认配置开始
        self._config = self._deep_copy(self._default_config)
        
        # 加载配置文件
        if self.config_file and os.path.exists(self.config_file):
            file_config = self._load_config_file(self.config_file)
            self._config = self._deep_merge(self._config, file_config)
        
        # 加载环境变量
        env_config = self._load_env_config()
        self._config = self._deep_merge(self._config, env_config)
        
        # 验证配置
        self._validate_config()
        
        self._loaded = True
        logger.info("Configuration loaded successfully")
        return self._config
    
    def _load_config_file(self, config_file: str) -> Dict[str, Any]:
        """加载配置文件"""
        try:
            file_path = Path(config_file)
            if not file_path.exists():
                logger.warning(f"Config file not found: {config_file}")
                return {}
            
            with open(file_path, 'r', encoding='utf-8') as f:
                if file_path.suffix.lower() in ['.yml', '.yaml']:
                    config = yaml.safe_load(f)
                elif file_path.suffix.lower() == '.json':
                    config = json.load(f)
                else:
                    raise ConfigurationException(f"Unsupported config file format: {file_path.suffix}")
            
            logger.info(f"Loaded config from file: {config_file}")
            return config or {}
            
        except Exception as e:
            raise ConfigurationException(f"Failed to load config file {config_file}: {str(e)}")
    
    def _load_env_config(self) -> Dict[str, Any]:
        """加载环境变量配置"""
        env_config = {}
        prefix = f"{self.env_prefix}_"
        
        for key, value in os.environ.items():
            if key.startswith(prefix):
                # 移除前缀并转换为小写
                config_key = key[len(prefix):].lower()
                
                # 将下划线分隔的键转换为嵌套字典
                keys = config_key.split('_')
                current = env_config
                
                for k in keys[:-1]:
                    if k not in current:
                        current[k] = {}
                    current = current[k]
                
                # 尝试转换值类型
                current[keys[-1]] = self._convert_env_value(value)
        
        if env_config:
            logger.info(f"Loaded {len(env_config)} environment variables")
        
        return env_config
    
    def _convert_env_value(self, value: str) -> Union[str, int, float, bool]:
        """转换环境变量值类型"""
        # 布尔值
        if value.lower() in ('true', '1', 'yes', 'on'):
            return True
        elif value.lower() in ('false', '0', 'no', 'off'):
            return False
        
        # 数字
        try:
            if '.' in value:
                return float(value)
            else:
                return int(value)
        except ValueError:
            pass
        
        # 字符串
        return value
    
    def _validate_config(self):
        """验证配置"""
        errors = []
        
        for key_path, validator in self._validators.items():
            try:
                value = self._get_nested_value(self._config, key_path)
                validator.validate(value, key_path)
            except Exception as e:
                errors.append(f"{key_path}: {str(e)}")
        
        if errors:
            error_msg = "Configuration validation failed:\n" + "\n".join(errors)
            raise ConfigurationException(error_msg)
    
    def get(self, key: str, default: Any = None) -> Any:
        """获取配置值"""
        if not self._loaded:
            self.load_config()
        
        try:
            return self._get_nested_value(self._config, key)
        except KeyError:
            return default
    
    def set(self, key: str, value: Any):
        """设置配置值"""
        if not self._loaded:
            self.load_config()
        
        self._set_nested_value(self._config, key, value)
    
    def get_section(self, section: str) -> Dict[str, Any]:
        """获取配置段"""
        return self.get(section, {})
    
    def has(self, key: str) -> bool:
        """检查配置键是否存在"""
        if not self._loaded:
            self.load_config()
        
        try:
            self._get_nested_value(self._config, key)
            return True
        except KeyError:
            return False
    
    def update(self, config: Dict[str, Any]):
        """更新配置"""
        if not self._loaded:
            self.load_config()
        
        self._config = self._deep_merge(self._config, config)
        self._validate_config()
    
    def save_config(self, file_path: str, format: str = 'yaml'):
        """保存配置到文件"""
        if not self._loaded:
            raise ConfigurationException("No configuration loaded")
        
        try:
            file_path_obj = Path(file_path)
            file_path_obj.parent.mkdir(parents=True, exist_ok=True)
            
            with open(file_path_obj, 'w', encoding='utf-8') as f:
                if format.lower() in ['yml', 'yaml']:
                    yaml.dump(self._config, f, default_flow_style=False, indent=2)
                elif format.lower() == 'json':
                    json.dump(self._config, f, indent=2, ensure_ascii=False)
                else:
                    raise ConfigurationException(f"Unsupported format: {format}")
            
            logger.info(f"Configuration saved to: {file_path}")
            
        except Exception as e:
            raise ConfigurationException(f"Failed to save config: {str(e)}")
    
    def reload(self):
        """重新加载配置"""
        logger.info("Reloading configuration")
        self._loaded = False
        return self.load_config()
    
    def get_all(self) -> Dict[str, Any]:
        """获取所有配置"""
        if not self._loaded:
            self.load_config()
        return self._deep_copy(self._config)
    
    def _get_nested_value(self, data: Dict[str, Any], key_path: str) -> Any:
        """获取嵌套字典值"""
        keys = key_path.split('.')
        current = data
        
        for key in keys:
            if not isinstance(current, dict) or key not in current:
                raise KeyError(f"Key '{key_path}' not found")
            current = current[key]
        
        return current
    
    def _set_nested_value(self, data: Dict[str, Any], key_path: str, value: Any):
        """设置嵌套字典值"""
        keys = key_path.split('.')
        current = data
        
        for key in keys[:-1]:
            if key not in current:
                current[key] = {}
            current = current[key]
        
        current[keys[-1]] = value
    
    def _deep_copy(self, obj: Any) -> Any:
        """深拷贝对象"""
        import copy
        return copy.deepcopy(obj)
    
    def _deep_merge(self, base: Dict[str, Any], update: Dict[str, Any]) -> Dict[str, Any]:
        """深度合并字典"""
        result = self._deep_copy(base)
        
        for key, value in update.items():
            if key in result and isinstance(result[key], dict) and isinstance(value, dict):
                result[key] = self._deep_merge(result[key], value)
            else:
                result[key] = self._deep_copy(value)
        
        return result

class EnvironmentManager:
    """环境管理器"""
    
    def __init__(self):
        self.environment = self._detect_environment()
    
    def _detect_environment(self) -> str:
        """检测运行环境"""
        env = os.getenv('ENVIRONMENT', os.getenv('ENV', 'development')).lower()
        
        if env in ['prod', 'production']:
            return 'production'
        elif env in ['test', 'testing']:
            return 'testing'
        elif env in ['stage', 'staging']:
            return 'staging'
        else:
            return 'development'
    
    def is_development(self) -> bool:
        """是否为开发环境"""
        return self.environment == 'development'
    
    def is_testing(self) -> bool:
        """是否为测试环境"""
        return self.environment == 'testing'
    
    def is_staging(self) -> bool:
        """是否为预发布环境"""
        return self.environment == 'staging'
    
    def is_production(self) -> bool:
        """是否为生产环境"""
        return self.environment == 'production'
    
    def get_environment(self) -> str:
        """获取当前环境"""
        return self.environment
    
    def get_config_file(self, base_name: str = 'config') -> str:
        """根据环境获取配置文件名"""
        return f"{base_name}.{self.environment}.yaml"

class SecretManager:
    """密钥管理器"""
    
    def __init__(self, config_manager: ConfigManager):
        self.config_manager = config_manager
        self._secrets = {}
    
    def get_secret(self, key: str, default: str = None) -> str:
        """获取密钥"""
        # 首先尝试从环境变量获取
        env_key = f"SECRET_{key.upper()}"
        secret = os.getenv(env_key)
        
        if secret:
            return secret
        
        # 从配置中获取
        secret = self.config_manager.get(f"secrets.{key}", default)
        
        if secret is None:
            raise ConfigurationException(f"Secret '{key}' not found")
        
        return secret
    
    def set_secret(self, key: str, value: str):
        """设置密钥"""
        self._secrets[key] = value
    
    def has_secret(self, key: str) -> bool:
        """检查密钥是否存在"""
        try:
            self.get_secret(key)
            return True
        except ConfigurationException:
            return False

# 全局配置管理器实例
_config_manager = None
_environment_manager = None

def get_config_manager() -> ConfigManager:
    """获取全局配置管理器"""
    global _config_manager
    if _config_manager is None:
        env_manager = get_environment_manager()
        config_file = env_manager.get_config_file()
        _config_manager = ConfigManager(config_file)
        _config_manager.load_config()
    return _config_manager

def get_environment_manager() -> EnvironmentManager:
    """获取全局环境管理器"""
    global _environment_manager
    if _environment_manager is None:
        _environment_manager = EnvironmentManager()
    return _environment_manager

def get_config(key: str, default: Any = None) -> Any:
    """获取配置值（便捷函数）"""
    return get_config_manager().get(key, default)

def get_config_section(section: str) -> Dict[str, Any]:
    """获取配置段（便捷函数）"""
    return get_config_manager().get_section(section)

def is_development() -> bool:
    """是否为开发环境（便捷函数）"""
    return get_environment_manager().is_development()

def is_production() -> bool:
    """是否为生产环境（便捷函数）"""
    return get_environment_manager().is_production()